<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Jc</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        body{
            display: flex;
            justify-content: center;
            align-items: center;
            width: 100%;
            min-height: 100vh;
        }
        canvas {
            width: 350px;
            height: 180px;
            background-color: #000;
        }
    </style>
</head>

<body>
    <canvas id='canvas'></canvas>
</body>
<script>
    // 创建一些全局变量
    let canvas = document.getElementById('canvas'),
        ctx = canvas.getContext('2d'),
        c_width = canvas.width,
        c_height = canvas.height;

    //辅助函数
    function random(min, max) {
        return Math.random() * (max - min) + min;
    }
    // console.log(random(1,100))
    // 蛇对象
    function Snake() {
        // 初始化时蛇的节点数量
        this.num = 4;
        // 每个蛇节点的宽度
        this.w = 4;
        // 装载蛇身体的数组
        this.body = [];
        // 蛇的方向
        this.diretion = 'right';
        // 蛇的存活状态
        this.isLive = true;
        //分数
        this.score = 0;
        // 初始化蛇身数据
        for (let i = 0; i < this.num; i++) {
            this.body.push({ x: i, y: 0 });
        }
        // 蛇的食物
        this.food = { x: Math.floor(random(1, c_width / this.w)), y: Math.floor(random(1, c_height / this.w)) }
    }
    // 绘制蛇的身体
    Snake.prototype.render = function () {
        // 画出蛇的头部
        let header_node = this.body[0];
        ctx.fillStyle = "#f00";
        ctx.fillRect(header_node.x * this.w, header_node.y * this.w, this.w, this.w)
        ctx.fillStyle = "#ff0";
        ctx.strokeRect(header_node.x * this.w, header_node.y * this.w, this.w, this.w)
        // 画蛇的身体
        for (let i = 1; i < this.num; i++) {
            let node = this.body[i];
            ctx.fillStyle = "#ff0";
            ctx.fillRect(node.x * this.w, node.y * this.w, this.w, this.w)
            ctx.fillStyle = "#f00";
            ctx.strokeRect(node.x * this.w, node.y * this.w, this.w, this.w)
        }

        //画蛇的食物
        ctx.fillStyle = "#0f0";
        ctx.fillRect(this.food.x * this.w, this.food.y * this.w, this.w, this.w)
        ctx.fillStyle = "#0f0";
        ctx.strokeRect(this.food.x * this.w, this.food.y * this.w, this.w, this.w)

        // 绘制分数
        ctx.fillStyle = "#fff"
        ctx.fillText(this.score, this.w, this.w * 2);
    }

    Snake.prototype.update = function () {
        let head_x = this.body[0].x,
            head_y = this.body[0].y;
        //控制蛇的前进方向
        if (this.diretion == 'right') {// 向右走
            head_x++;
            if (this.w * head_x >= c_width) {
                // console.log('撞到右边的墙')
                // head_x=0;
                this.isLive = false;
            }
        } else if (this.diretion == 'left') {//向左走
            head_x--;
            if (head_x <= 0) {
                // head_x=Math.floor(c_width/this.w);
                this.isLive = false;
            }
        } else if (this.diretion == 'up') {//向上走
            head_y--;
            if (head_y <= 0) {
                // head_y=Math.floor(c_height/this.w);
                this.isLive = false;
            }
        } else if (this.diretion == 'down') {//向下走
            head_y++;
            if (head_y * this.w >= c_height) {
                // head_y=0;
                this.isLive = false;
            }
        }
        if (this.food.x == head_x && this.food.y == head_y) {
            // 如果吃到食物，那么就把食物节点放到蛇数组的最后即可
            tail = { x: head_x, y: head_y }
            // 吃到食物蛇的长度加一
            this.num++
            //再随机一个食物出来
            this.food = { x: Math.floor(random(1, c_width / this.w)), y: Math.floor(random(1, c_height / this.w)) }
            // 吃到食物，分数加一
            this.score++;
        } else {
            // 没有吃到食物的话，还是常规的前进
            tail = this.body.pop();
            tail.x = head_x;
            tail.y = head_y;
        }

        this.body.unshift(tail);
    }
    // 添加文档对象的键盘监听
    document.addEventListener("keydown", function (e) {
        e = e || window.event;
        let kc = e.keyCode;
        console.log(e.keyCode);
        // 上键->38 下键->40 左键->37 右键->39
        if (kc == 38) {
            //如果正在向下跑，则不准直接向上跑，实际就是不准直接返回
            if (snake.diretion != 'down') {
                snake.diretion = 'up';
            }

        } else if (kc == 40) {
            if (snake.diretion != 'up') {
                snake.diretion = 'down';
            }

        } else if (kc == 37) {
            if (snake.diretion != 'right') {
                snake.diretion = 'left';
            }

        } else if (kc == 39) {
            if (snake != 'left') {
                snake.diretion = 'right';
            }

        } else if (kc == 66) {//按下键盘B键，重新开始游戏
            snake = new Snake()
            lock = setInterval(run, 55);
        }
    })
    let snake = new Snake()
    // snake.render()
    function run() {
        if (snake.isLive) {
            // 用背景颜色清屏
            ctx.fillStyle = "#000";
            ctx.fillRect(0, 0, c_width, c_height);

            snake.render();
            snake.update();
        } else {
            //    console.log('game over');
            //    先清屏一下
            ctx.fillStyle = "#000";
            ctx.fillRect(0, 0, c_width, c_height);
            ctx.fillStyle = "#fff"
            ctx.textAlign = 'center';
            ctx.fillText("Game over!", c_width / 2, c_height / 2);
            ctx.fillText("Press B start again", c_width / 2, c_height / 2 + 15);
            clearInterval(lock);
        }
    }
    var lock = setInterval(run, 55);
</script>

</html>